package com.irdstudio.rsp.drools.service.impl;

import com.alibaba.fastjson.JSON;
import com.irdstudio.rsp.drools.beans.RuleBean;
import com.irdstudio.rsp.drools.beans.RuleBean.RESULT;
import com.irdstudio.rsp.drools.beans.RuleParamBean;
import com.irdstudio.rsp.drools.common.BizRuleAgendaFilter;
import com.irdstudio.rsp.drools.exception.FireRuleErrorEnum;
import com.irdstudio.rsp.drools.exception.FireRuleException;
import com.irdstudio.rsp.drools.service.FireRuleService;
import com.irdstudio.rsp.rule.common.constant.Constant;
import com.irdstudio.rsp.rule.common.constant.Constant.RULE_COLL_STATE;
import com.irdstudio.rsp.rule.common.constant.Constant.RULE_COLL_TYPE;
import com.irdstudio.rsp.rule.common.constant.Constant.YES_OR_NO;
import com.irdstudio.rsp.rule.dao.BizRuleAdapterDao;
import com.irdstudio.rsp.rule.dao.SRuleCollInfoDao;
import com.irdstudio.rsp.rule.dao.domain.BizRuleAdapter;
import com.irdstudio.rsp.rule.dao.domain.SRuleCollInfo;
import com.irdstudio.rsp.rule.service.facade.SRuleCollInfoService;
import com.irdstudio.rsp.rule.service.vo.BizRuleAdapterVO;
import com.irdstudio.rsp.rule.service.vo.SRuleCollInfoVO;
import com.irdstudio.sdk.admin.dao.SDicDao;
import com.irdstudio.sdk.admin.dao.domain.SDic;
import com.irdstudio.sdk.admin.service.vo.SDicVO;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.StringUtils;
import org.kie.api.KieBase;
import org.kie.api.cdi.KBase;
import org.kie.api.runtime.KieSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeansException;
import org.springframework.beans.PropertyAccessorFactory;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

@Service("fireRuleServiceImpl")
public class FireRuleServiceImpl implements FireRuleService, BeanFactoryAware {

    private static Logger log = LoggerFactory.getLogger(FireRuleServiceImpl.class);

    @KBase("KBase_biz")
    private KieBase kbase;

    @Autowired
    private SRuleCollInfoDao sRuleCollInfoDao;

    @Autowired
    private SDicDao sDicDao;

    @Autowired
    private BizRuleAdapterDao bizRuleAdapterDao;

    @Autowired
    @Qualifier("sRuleCollInfoServiceImpl")
    private SRuleCollInfoService sRuleCollInfoService;


    @Override
    public Map<String, Object> list(Map<String, Object> request) {
        // 查询条件
        Map<String, Object> input = MapUtils.getMap(request, "input");
        // 分页信息
        Map<String, Object> page = MapUtils.getMap(request, "pageInfo");

        SRuleCollInfoVO sRuleCollVo = new SRuleCollInfoVO();
        BeanWrapper wrapper = PropertyAccessorFactory.forBeanPropertyAccess(sRuleCollVo);
        wrapper.setAutoGrowNestedPaths(true);
        wrapper.setPropertyValues(input);
        wrapper.setPropertyValues(page);

        // 限制每页条数不能超过100
        if (sRuleCollVo.getSize() > 100) {
            sRuleCollVo.setSize(100);
        }

        Map<String, Object> resp = new HashMap<>();
        // 查询规则集配置
        List<SRuleCollInfoVO> sRuleColls = sRuleCollInfoService.queryAllOwner(sRuleCollVo);
        // 翻译规则集名称
        if (CollectionUtils.isNotEmpty(sRuleColls)) {
            SDicVO dicParam = new SDicVO();
            dicParam.setOpttype("RULE_COLL_TYPE");
            List<SDic> dics = sDicDao.queryAllOwnerByPage(dicParam);
            for (SRuleCollInfoVO info : sRuleColls) {
                String collType = info.getRuleCollType();
                if (collType != null) {
                    if (CollectionUtils.isNotEmpty(dics)) {
                        for (SDic dic : dics) {
                            if (dic.getEnname().equals(collType)) {
                                info.setRuleCollTypeName(dic.getCnname());
                                break;
                            }
                        }
                    }
                }
            }
        }
        page.put("total", sRuleCollVo.getTotal());
        resp.put("sruleCollList", sRuleColls);
        resp.put("pageInfo", page);
        return resp;
    }

    @Override
    public Map<String, Object> fire(RuleBean ruleBean) {
        List<String> ruleCollIds = null;
        if (CollectionUtils.isEmpty(ruleBean.getRuleCollIds())) {
            // 规则集id为空， 则根据适配条件查找对应的规则集
            // 规则集的有效性在执行时检查
            ruleCollIds = findRuleCollIds(ruleBean);
        } else {
            // 检查是否有空字符串
            ruleCollIds = new ArrayList<>(ruleBean.getRuleCollIds().size());
            for (String id : ruleBean.getRuleCollIds()) {
                if (StringUtils.isNotBlank(id)) {
                    ruleCollIds.add(id);
                }
            }
        }

        // 遍历执行
        for (String ruleCollId : ruleCollIds) {
            if (StringUtils.isBlank(ruleCollId)) {
                throw new FireRuleException(FireRuleErrorEnum.E_EMPTY_RULE_COLL_ID.getCode(), FireRuleErrorEnum.E_EMPTY_RULE_COLL_ID.getMessage());
            }
            // 查询规则集配置
            SRuleCollInfo sruleColl = new SRuleCollInfo();
            sruleColl.setRuleCollId(ruleCollId);
            sruleColl = sRuleCollInfoDao.queryByPk(sruleColl);
            if (!checkRuleColl(sruleColl)) {
                throw new FireRuleException(FireRuleErrorEnum.E_RULE_COLL_INVALID.getCode(), FireRuleErrorEnum.E_RULE_COLL_INVALID.getMessage(ruleCollId));
            }
            // 查询规则参数配置
            List<RuleParamBean> ruleDtlParamList = null;
            try {
                ruleDtlParamList = sRuleCollInfoDao.querySRuleCollParamByRuleSetId(ruleCollId);
            } catch (Exception e) {
                log.error(e.getMessage(), e);
                throw new FireRuleException(FireRuleErrorEnum.E_DB_EXCEPTION.getCode(), FireRuleErrorEnum.E_DB_EXCEPTION.getMessage(), e);
            }

            if (CollectionUtils.isNotEmpty(ruleDtlParamList)) {
                BizRuleAgendaFilter filter = new BizRuleAgendaFilter();
                for (RuleParamBean dtl : ruleDtlParamList) {
                    // 规则ID
                    String ruleId = dtl.getRuleId();
                    String ruleName = dtl.getRuleName();
                    String ruleType = dtl.getRuleType();
                    String paramId = dtl.getParamId();
                    String paramConf = dtl.getParamConf();
                    filter.getRuleSet().add(ruleId);
                    // 判断是否有参数配置
                    Map<String, Object> param = MapUtils.getMap(ruleBean.getParam(), ruleId);
                    if (param == null) {
                        param = new HashMap<>();
                        ruleBean.getParam().put(ruleId, param);
                    }
                    if (StringUtils.isNotBlank(paramConf)) {
                        // 设置规则参数
                        String key = dtl.getParamConf();
                        // 参数统一是按字符串记录
                        String val = dtl.getParamVal();
                        param.put(key, val);
                    }
                    param.put(RuleBean.RULE_NAME_KEY, ruleName); // 输出执行的规则id与名称
                    param.put(RuleBean.RULE_TYPE_KEY, ruleType); // 输出执行的规则类型
                }
                // 设置当前执行规则集id
                ruleBean.setCurrentRuleCollId(ruleCollId);
                ruleBean = proxyFireRule(ruleBean, filter);
            }
        }

        // 处理返回结果
        Map<String, Object> resp = new HashMap<>();
        resp.put("output", ruleBean.getOutput());
        return resp;
    }

    /**
     * 规则集为空的时候，需要根据以下条件去查询对应的规则集
     *
     * @param ruleBean
     * @return
     */
    private List<String> findRuleCollIds(RuleBean ruleBean) {
        Set<String> ruleCollIds = new LinkedHashSet<>();

        if (StringUtils.isNotBlank(ruleBean.getRuleCollType())) {
            // 规则集类型不为空， 且为审批大纲时，查找生效的审批大纲规则集
            RULE_COLL_TYPE type = Constant.get(RULE_COLL_TYPE.class, ruleBean.getRuleCollType());
            if (RULE_COLL_TYPE.Approval == type) {
                SRuleCollInfoVO collInfoVO = new SRuleCollInfoVO();
                collInfoVO.setRuleCollType(type.getCode());
                collInfoVO.setRuleCollState(RULE_COLL_STATE.VALID.getCode());
                List<SRuleCollInfo> sRuleCollInfos = sRuleCollInfoDao.queryAllOwnerByPage(collInfoVO);
                if (CollectionUtils.isNotEmpty(sRuleCollInfos) && sRuleCollInfos.size() == 1) {
                    SRuleCollInfo info = sRuleCollInfos.get(0);
                    ruleCollIds.add(info.getRuleCollId());
                }
            } else if (RULE_COLL_TYPE.SpecialApproval == type) {
                // 特批审批大纲
                // 先找全部的
                BizRuleAdapterVO adapterVO = new BizRuleAdapterVO();
                adapterVO.setRuleTargetType(type.getCode()); // 目标规则集类型
                adapterVO.setAdapterCustomDim2(YES_OR_NO.YES.getCode()); // 特批适配配置
                adapterVO.setAdapterOrgNo("");
                adapterVO.setAdapterCustomDim1("");
                List<BizRuleAdapter> adapterList = bizRuleAdapterDao.queryAllAdapter(adapterVO);
                if (CollectionUtils.isNotEmpty(adapterList)) {
                    for (BizRuleAdapter el : adapterList) {
                        String collId = el.getRuleTargetId();
                        SRuleCollInfo collInfo = sRuleCollInfoDao.queryByRuleCollId(collId);
                        if (checkRuleColl(collInfo)) {
                            ruleCollIds.add(collId);
                        }
                    }
                }
                // 找出仅机构适配的
                adapterVO.setAdapterOrgNo(ruleBean.getOrgNo());
                adapterVO.setAdapterCustomDim1("");
                adapterList = bizRuleAdapterDao.queryAllAdapter(adapterVO);
                if (CollectionUtils.isNotEmpty(adapterList)) {
                    for (BizRuleAdapter el : adapterList) {
                        String collId = el.getRuleTargetId();
                        SRuleCollInfo collInfo = sRuleCollInfoDao.queryByRuleCollId(collId);
                        if (checkRuleColl(collInfo)) {
                            ruleCollIds.add(collId);
                        }
                    }
                }
                // 找出仅城市适配的
                adapterVO.setAdapterOrgNo("");
                adapterVO.setAdapterCustomDim1(ruleBean.getCustomDimOne());
                adapterList = bizRuleAdapterDao.queryAllAdapter(adapterVO);
                if (CollectionUtils.isNotEmpty(adapterList)) {
                    for (BizRuleAdapter el : adapterList) {
                        String collId = el.getRuleTargetId();
                        SRuleCollInfo collInfo = sRuleCollInfoDao.queryByRuleCollId(collId);
                        if (checkRuleColl(collInfo)) {
                            ruleCollIds.add(collId);
                        }
                    }
                }
                // 机构与城市适配的
                adapterVO.setAdapterOrgNo(ruleBean.getOrgNo());
                adapterVO.setAdapterCustomDim1(ruleBean.getCustomDimOne());
                adapterList = bizRuleAdapterDao.queryAllAdapter(adapterVO);
                if (CollectionUtils.isNotEmpty(adapterList)) {
                    for (BizRuleAdapter el : adapterList) {
                        String collId = el.getRuleTargetId();
                        SRuleCollInfo collInfo = sRuleCollInfoDao.queryByRuleCollId(collId);
                        if (checkRuleColl(collInfo)) {
                            ruleCollIds.add(collId);
                        }
                    }
                }
            }
        }
        // 查找其它适配规则集
        String orgNo = ruleBean.getOrgNo(); // 适配机构
        String prdCode = ruleBean.getPrdCode(); // 适配产品代码
        String flowId = ruleBean.getFlowId(); //适配流程id
        String sysCode = ruleBean.getSysCode(); // 适配业务系统代码
        String adapter_custom_dim1 = ruleBean.getCustomDimOne(); //适配的自定义维度1
        String adapter_custom_dim2 = ruleBean.getCustomDimTwo(); //适配的自定义维度2
        BizRuleAdapterVO adapterVO = new BizRuleAdapterVO();
        adapterVO.setAdapterOrgNo(orgNo);
        adapterVO.setAdapterPrdCode(prdCode);
        adapterVO.setAdapterFlowId(flowId);
        adapterVO.setAdapterSysCode(sysCode);
        adapterVO.setAdapterCustomDim1(adapter_custom_dim1);
        adapterVO.setAdapterCustomDim2(adapter_custom_dim2);
        List<BizRuleAdapter> adapterRuleColls = bizRuleAdapterDao.queryAll(adapterVO);
        if (CollectionUtils.isNotEmpty(adapterRuleColls)) {
            for (BizRuleAdapter adapter : adapterRuleColls) {
                String ruleCollId = adapter.getRuleTargetId(); // 适配的规则集id
                SRuleCollInfo collInfo = sRuleCollInfoDao.queryByRuleCollId(ruleCollId);
                if (checkRuleColl(collInfo)) {
                    ruleCollIds.add(ruleCollId);
                }
            }
        }

        return new ArrayList<>(ruleCollIds);
    }

    /**
     * 检查规则集的有效性
     * @param collInfo
     * @return
     */
    private boolean checkRuleColl(SRuleCollInfo collInfo) {
        if (collInfo == null) {
            return false;
        }
        if (StringUtils.isBlank(collInfo.getRuleCollState())) {
            return false;
        }
        if (collInfo.getRuleCollState().equals(RULE_COLL_STATE.INVALID.getCode())) {
            return false;
        }
        return true;
    }

    /**
     * 执行规则集
     *
     * @param ruleBean 入参
     * @param filter   指定规则执行
     * @return ruleBean
     */
    @Override
    public RuleBean fireRule(RuleBean ruleBean, BizRuleAgendaFilter filter) {
        // 打印规则入参
        if (log.isDebugEnabled()) {
            log.debug("规则入参\n {}", JSON.toJSONString(ruleBean));
        }
        KieSession session = kbase.newKieSession();
        try {
            session.insert(ruleBean);
            session.fireAllRules(filter);
        } catch (Exception e) {
            throw new FireRuleException(FireRuleErrorEnum.E_EXEC_EXCEPTION.getCode(), FireRuleErrorEnum.E_EXEC_EXCEPTION.getMessage(ruleBean.getCurrentRuleCollId()), e);
        } finally {
            session.dispose();
        }
        // 打印规则出参
        if (log.isDebugEnabled()) {
            log.debug("规则出参\n {}", JSON.toJSONString(ruleBean));
        }
        // 处理结果
        Set<String> acceptSet = new LinkedHashSet<>(filter.getRuleSet());
        // 取差集 得到执行通过的规则
        acceptSet.removeAll(ruleBean.getRefuseSet());
        for (String ruleId : acceptSet) {
            ruleBean.setResult(ruleId, RESULT.ACCEPT, "通过");
        }

        // 打印规则出参
        if (log.isDebugEnabled()) {
            // 开发输出，便于调试
            log.debug("规则处理后的出参\n {}", JSON.toJSONString(ruleBean));
            log.debug("refuseSet: {}", ruleBean.getRefuseSet());
            log.debug("acceptSet: {}", ruleBean.getAcceptSet());
        }
        // 清理列表，为下一次执行准备
        ruleBean.getRefuseSet().clear();
        ruleBean.getAcceptSet().clear();
        return ruleBean;
    }

    /**
     * this proxy
     */
    private FireRuleService proxyObj;

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        proxyObj = beanFactory.getBean("fireRuleServiceImpl", FireRuleService.class);
    }

    /**
     * 走代理调用fireRule 使方法调用走日志切面
     *
     * @param ruleBean
     * @param filter
     * @return
     */
    private RuleBean proxyFireRule(RuleBean ruleBean, BizRuleAgendaFilter filter) {
        return proxyObj.fireRule(ruleBean, filter);
    }
}
